/*
 * $Id: dictc.cc 9ce65bed8ef4 2012/08/26 02:14:51 pgurumur $
 * Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *

 * __version__  = "$Revision: 9ce65bed8ef4 $"
 * __author__   = "$Author: pgurumur $"
 * __modified__ = "$Date: 2012-08-26 02:14:51Z $"
 */
#include "dictc.h"

namespace dict {

   dictClient::dictClient () : __af(0), __sock(0), __port(DictPort), __server(0)
   {
      memset(&__sin4, 0, sizeof(struct sockaddr_in));
      memset(&__sin6, 0, sizeof(struct sockaddr_in6));
   }

   dictClient::dictClient (const dictClient &Entry)
   {
      *this = Entry;
   }

   dictClient &
   dictClient::operator= (const dictClient &Entry)
   {
      Close();

      __af = Entry.__af;
      __sock = Entry.__sock;
      __port = Entry.__port;
      
      if (Entry.__server)
         __server = Entry.__server;

      memcpy(&__sin4, &Entry.__sin4, sizeof (struct sockaddr_in));
      memcpy(&__sin6, &Entry.__sin6, sizeof (struct sockaddr_in6));

      return *this;
   }

   dictClient::~dictClient()
   {
      Close ();
   }

   void
   dictClient::Close ()
   {
      if (__sock)
         close (__sock);

      if (__server)
         free (__server);
   }

   void
   dictClient::Connect (const char *Server, const u_int16_t Port = DictPort, 
         const int Af = PF_INET)
   {
      __af = Af;
      __port = Port;

      if (Server) {
         __server = (char *)malloc(strlen(Server) + 1);
         strlcpy (__server, Server, strlen(Server) + 1);

         struct hostent *host = gethostbyname2 (Server, __af);
         if (__af == PF_INET) {
            if (host)
               memcpy (&__sin4.sin_addr, host->h_addr_list[0], host->h_length);

            __sin4.sin_family = __af;
            __sin4.sin_port = htons (__port);
         }
         else if (__af == PF_INET6) {
            if (host)
               memcpy (&__sin6.sin6_addr, host->h_addr_list[0], host->h_length);

            __sin6.sin6_family = __af;
            __sin6.sin6_port = htons (__port);
         }

         int protocol = 0;
         char *tcpProto = "tcp";
         struct protoent *proto;
         if ((proto = getprotobyname(tcpProto)) != NULL)
            protocol = proto->p_proto;

         __sock = socket (__af, SOCK_STREAM, protocol);
         if (__sock < 0)
            err (1, "socket()");

         int setOpt = 0;
         const u_int32_t recvBuf = CmdLineBuf;
         setOpt = setsockopt (__sock, SOL_SOCKET, SO_RCVBUF, &recvBuf, 
               sizeof(u_int32_t));

         nonBlock ();

         int retval = 0;
         if (__af == PF_INET) 
            retval = connect (__sock, (struct sockaddr *)&__sin4, 
                  sizeof (__sin4));
         else if (__af == PF_INET6)
            retval = connect (__sock, (struct sockaddr *)&__sin6, 
                  sizeof (__sin6));

         if ((retval != 0) || (retval != EINPROGRESS))
            err (1, "connect()");

         unBlock ();
      }
   }

   void
   dictClient::nonBlock ()
   {
      int value = fcntl (__sock, F_GETFL);
      if (value < 0)
         err (1, "fcntl()");

      if (!(value & O_NONBLOCK)) {
         value |= O_NONBLOCK;
         if (fcntl (__sock, F_SETFL, value) < 0)
            err (1, "fcntl()");
      }

   }

   void
   dictClient::unBlock ()
   {
      int value = fcntl (__sock, F_GETFL);
      if (value < 0)
         err (1, "fcntl()");

      if (value & O_NONBLOCK) {
         value &= ~O_NONBLOCK;
         if (fcntl (__sock, F_SETFL, value) < 0)
            err (1, "fcntl()");
      }
   }

   void 
   dictClient::sockRead (char *buffer)
   {
      buffer = (char *)malloc(CmdLineBuf);
      struct pollfd pfd[1];
      int nfds = 0;
      int length = 0;

      pfd[0].fd = __sock;
      pfd[0].events = POLLIN;

      int flag = 1;
      while (flag) {
         nfds = poll (pfd, 1, 1000);
         if (nfds == 0)
            flag = 0;
         else {
            if ((nfds == -1) || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)))
               err(1, "poll()");

            length = read (__sock, buffer, sizeof (buffer));
         }
      }
   }

   void
   dictClient::sockWrite (const char *Buffer)
   {
      if (Buffer) {
         struct pollfd pfd[1];
         int nfds = 0;
         int writeBytes = 0;

         pfd[0].fd = __sock;
         pfd[0].events = POLLOUT;

         nfds = poll (pfd, 1, 6000);
         if ((nfds == -1) || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)))
            err (1, "poll()");

         if (nfds == 0)
            err (1, "timeout poll()");

         writeBytes = write (__sock, Buffer, strlen (Buffer));
         if (writeBytes < 0)
            err (1, "write()");

      }
   }


   cmdLineEdit::cmdLineEdit () : __edit(0), __hist(0) 
   {
      __edit = el_init(__progname, stdin, stdout, stderr);
      __hist = history_init();

      const char *DictEditor = "emacs";
      const char *DictPrompt = "dict> ";
      history (__hist, &__histEvent, H_SETSIZE, MaxHistory);
      el_set (__edit, EL_HIST, history, __hist);
      el_set (__edit, EL_EDIT, DictEditor);
      el_set (__edit, EL_PROMPT, DictPrompt);
      el_source (__edit, NULL);
      el_set (__edit, EL_SIGNAL, 1);
   }

   cmdLineEdit::cmdLineEdit (const cmdLineEdit &Entry)
   {
      *this = Entry;
   }

   cmdLineEdit &
   cmdLineEdit::cmdLineEdit (const cmdLineEdit &Entry)
   {
      Close ();
      __edit = Entry.__edit;
      __hist = Entry.__hist;
      __histEvent = Entry.__histEvent;

   }

   void
   cmdLineEdit::cmdPrompt ()
   {
      size_t length = 0;
      const char *buf;
      fputc('\n', stdout);
      printf ("type 'help' any time to get help directly from the server\n");

      int flag = 1;
      while (flag) {
         buf = el_gets (__edit, (int *)&length);
         size_t bufLen = strlen(buf);
         if (bufLen != length)
            length = bufLen;

         if (length > 1) {
            if (buf[--length] == '\n')
               if (!length)
                  warning ("too few parameters in CLI");

            if (length >= MaxCmdLine)
               warning ("input line too long");
            else {
               char line[MaxCmdLine];
               memset (line, '\0', MaxCmdLine);
               memset (line, buf, length);
               flag = parseCmd (line);
            }
         }
      }
   }

   int
   cmdLineEdit::parseCmd (const char *Line)
   {
      if (Line) {
         :q






}

